package com.alit.ibot.robot.wechat.util;

import java.io.IOException;
import java.io.StringReader;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import com.alit.ibot.robot.projectvariable.PVK;
import com.alit.ibot.robot.projectvariable.ProjectVariableUtil;
import com.qq.weixin.mp.aes.AesException;
import com.qq.weixin.mp.aes.WXBizMsgCrypt;

/**
 * 加密和解密微信消息
 * 
 * @author litong
 * @date 2019年5月31日_上午10:07:14
 * @version 1.0
 * @desc
 */
public class WechatCryptUtil {
  private static WXBizMsgCrypt wxMsgCrypt = null;
  private static DocumentBuilder builer = null;
  // 外部程序可以访问isCrypt判断微信发送的消息是否加密
  public static boolean isCrypt;
  static {
    initDocumentBuilder();
  }

  /**
   * 初始化wxMsgCrypt
   */
  private static void initWxMsgCrypt() {
    String appId = ProjectVariableUtil.getValue(PVK.wechatAppId);
    String token = ProjectVariableUtil.getValue(PVK.wechatToken);
    String encodingAesKey = ProjectVariableUtil.getValue(PVK.wechatEncodingAESKey);
    try {
      wxMsgCrypt = new WXBizMsgCrypt(token, encodingAesKey, appId);
    } catch (AesException e) {
      e.printStackTrace();
    }
  }

  private static void initDocumentBuilder() {
    DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
    documentBuilderFactory.setIgnoringElementContentWhitespace(true);
    try {
      builer = documentBuilderFactory.newDocumentBuilder();
    } catch (ParserConfigurationException e) {
      e.printStackTrace();
    }
  }

  /**
   * 判断是否加密,如果有加密,则进行解密
   */
  public static String getFromXML(String xml, String msgSignature, String timestamp, String nonce)
      throws SAXException, IOException {
    StringReader sr = new StringReader(xml);
    InputSource is = new InputSource(sr);
    Document document = builer.parse(is);// 解析xml文件流到dom中
    Element rootElement = document.getDocumentElement();
    NodeList nodelist1 = rootElement.getElementsByTagName("Encrypt");
    int length = nodelist1.getLength();
    String retval = null;
    if (length > 0) { // 处理密文消息
      isCrypt = true; // 将密文消息的旗标设置为true
      String encrypt = nodelist1.item(0).getTextContent();// 加密后的内容
      retval = getCryptXML(encrypt, msgSignature, timestamp, nonce);
      return retval;
    } else { // 处理明文消息
      isCrypt = false;
      retval = xml;
    }
    return retval;
  }

  /**
   * 解密密微信消息
   * 
   * @param document
   * @return
   */
  private static String getCryptXML(String encrypt, String msgSignature, String timestamp, String nonce) {
    initWxMsgCrypt(); // 每次解密前都初始化wxMsgCrypt
    String format = "<xml><ToUserName><![CDATA[toUser]]></ToUserName><Encrypt><![CDATA[%1$s]]></Encrypt></xml>";
    String fromXML = String.format(format, encrypt);
    String result = null;
    try {
      result = wxMsgCrypt.decryptMsg(msgSignature, timestamp, nonce, fromXML);
    } catch (AesException e) {
      e.printStackTrace();
    }
    return result;
  }

  /**
   * 加密微信消息
   * 
   * @param toXML
   * @param timestamp
   * @param nonce
   */
  public static String getToXML(String toXML, String timestamp, String nonce) {
    String encryptMsg = null;
    try {
      encryptMsg = wxMsgCrypt.encryptMsg(toXML, timestamp, nonce);
    } catch (AesException e) {
      e.printStackTrace();
    }
    return encryptMsg;
  }
}
